<template>
  <div
    class="tinymce-editor"
    :class="{ 'is-readonly': readonly, 'no-padding-bottom': codeSnippet && commentNoPadding }"
  >
    <html-preview v-if="readonly && !codeSnippet" :content="myValue" />
    <editor v-else v-model="myValue" :init="init" :disabled="disabled || readonly" />
  </div>
</template>

<script>
import tinymce from 'tinymce/tinymce';
import axios from '@/utils/http';
import Editor from '@tinymce/tinymce-vue';
import 'tinymce/icons/default';
import 'tinymce/themes/silver';
import 'tinymce/plugins/table'; // 插入表格插件
import 'tinymce/plugins/lists'; // 列表插件
import 'tinymce/plugins/image';
import './plugins-change/quickbars';
import 'tinymce/plugins/imagetools';
import 'tinymce/plugins/paste';
import 'tinymce/plugins/autolink';
import 'tinymce/plugins/link';
import 'tinymce/plugins/searchreplace';
import 'tinymce/plugins/charmap';
import 'tinymce/plugins/hr';
import 'tinymce/plugins/emoticons';
import 'tinymce/plugins/anchor';
import 'tinymce/plugins/autoresize';
import './plugins-change/codesample';
import config from './editor_config';
import HtmlPreview from './html-preview';

export default {
  name: 'tinymce-editor',
  components: {
    Editor,
    HtmlPreview,
  },
  props: {
    value: {
      type: String,
      default: '',
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    height: {
      type: Number,
      default: 300,
    },
    readonly: {
      type: Boolean,
      default: false,
    },
    commentNoPadding: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      myValue: this.value,
      init: {
        height: this.height,
        plugins: this.readonly ? `${config.plugins} autoresize` : config.plugins,
        toolbar: config.toolbar,
        // 更多详细配置
        ...config.otherConfigs,
        images_upload_handler: (blobInfo, success, failure, progress) => {
          this.imageUpload(blobInfo, success, failure, progress);
        },
        imagetools_fetch_image: img => {
          return new tinymce.util.Promise(resolve => {
            self.handleImageUrlToBlob(img.src, resolve);
          });
      },
      },
    };
  },
  computed: {
    codeSnippet() {
      return this.value.indexOf('<pre class=') > -1;
    },
  },
  mounted() {
    tinymce.init({});
  },
  methods: {
    setContent(val) {
      this.myValue = val;
    },
    getUploadToken() {
      return new Promise((resolve, reject) => {
        this.$api.other.uploadToken()
          .then(res => resolve(res.data.token))
          .catch((err) => {
            this.$message.error('获取上传密钥失败', err);
            reject(err);
          });
      });
    },
    async imageUpload(blobInfo, success, failure, progress) {
      progress(0);
      const token = await this.getUploadToken();
      const axiosInstance = axios.create({ withCredentials: false });
      const formData = new FormData();
      formData.append('file', blobInfo.blob());
      formData.append('token', token);
      formData.append('key', `ck-images-${new Date().getTime()}/${blobInfo.blob().name}`);
      formData.append('x:user_id', this.$store.state.currentUser.id);
      axiosInstance({
        method: 'POST',
        url: 'https://up-z2.qiniup.com',
        data: formData,
        timeout: 30000,
        onUploadProgress: (progressEvent) => {
          progress((progressEvent.loaded / progressEvent.total) * 100);
          
        },
      }).then(alert(res.data.url))
        .catch(err => failure(err));
    },
    handleImageUrlToBlob (url, callback) {
      function imageToCanvas (src, cb) {
        const canvas = document.createElement('canvas')//创建画布
        const ctx = canvas.getContext('2d')   //画布
        const img = new Image()
        img.src = src + '?t=2'
        img.crossOrigin = ''
        img.onload = function () {
          canvas.width = img.width
          canvas.height = img.height
          ctx.drawImage(img, 0, 0)
          cb(canvas)
        }
      }

      function dataURLToBlob (dataURL) {
        const arr = dataURL.split(',')
        const mime = arr[ 0 ].match(/:(.*?);/)[ 1 ]
        const bStr = atob(arr[ 1 ])
        let n = bStr.length
        const u8arr = new Uint8Array(n)
        while (n--) {
          u8arr[ n ] = bStr.charCodeAt(n)
        }
        return new Blob([ u8arr ], { type: mime })
      }

      function canvasToDataURL (canvas, format, quality) {
        return canvas.toDataURL(format || 'image/jpeg', quality || 1.0)
      }

      imageToCanvas(url, (canvas) => {
        callback(dataURLToBlob(canvasToDataURL(canvas)))
      })
    }
  },
  watch: {
    myValue(val) { this.$emit('input', val); },
  },
};
</script>

<style lang="scss">
.tinymce-editor.is-readonly {

  &.no-padding-bottom { margin-bottom: -50px; }  // 不知道为什么在 readonly 模式下底部会多出50px（仅在包含代码块时调用tinymce）
  .tox-tinymce { border: none; }
  .tox-editor-header,
  .tox-statusbar { display: none; }

  ul{ list-style: disc inside; }
  ol{ list-style: decimal inside; }
  a {
    text-decoration: underline;
    color: -webkit-link;
  }
}
</style>
